
#ifdef INT
#  define TYP INTEGER
#else
#ifdef FLOAT
#  define TYP REAL
#else
 #error "Need to give MACRO definition for element type : -DTYPE_INT or -DTYPE_FLOAT"
#endif
#endif


PROGRAM PROG_PRINC
!
!compilation : gfortran prog_princ.f90 -fbounds-check
!
IMPLICIT NONE
!DECLARATION DES PARAMETRES


	! LA TAILLE DES MATRICES EST ENTREE EN LIGNE DE COMMANDE LORS DE L' EXECUTION
	INTEGER :: p = 0

	INTEGER :: DIM1
	INTEGER :: DIM2
	INTEGER :: NMAX
	INTEGER :: I,J
	INTEGER :: NBBANDESUP,NBBANDEINF,N
	
	CHARACTER*15 :: FORME

	INTEGER :: order
	CHARACTER(len=32) :: arg
	
 !********************POUR LE STOCKAGE COO
 TYP,DIMENSION(:),ALLOCATABLE :: VALUES !TABLEAU DE VALEURS
 INTEGER,DIMENSION(:,:),ALLOCATABLE :: INDICES !TABLEAU D'INDICES
 !********************POUR LE STOCKAGE CSR
 INTEGER,DIMENSION(:),ALLOCATABLE :: IA
 INTEGER,DIMENSION(:),ALLOCATABLE :: JA
 !********************POUR LE STOCKAGE EI
 TYP, DIMENSION (:,:), ALLOCATABLE :: AA
 INTEGER, DIMENSION (:,:), ALLOCATABLE :: BB
 !********************POUR LE STOCKAGE BANDE
 TYP, DIMENSION (:,:), ALLOCATABLE :: BANDE
 !********************POUR LA MATRICE PLEINE 
 TYP,DIMENSION(:),ALLOCATABLE :: U
 TYP, DIMENSION (:,:), ALLOCATABLE :: A
 INTEGER :: IERR

 TYP,DIMENSION(:),ALLOCATABLE :: V
 
	DO P=0,3
		CALL get_command_argument(p, arg)
		IF (LEN_TRIM(arg) == 0) exit 
			WRITE (*,*) TRIM(arg)
		IF (p == 1) THEN
			read ( arg , '(i10)') DIM1
		ELSEIF (P == 2) then
			READ ( ARG, '(I10)') DIM2
		ELSEIF (P == 3) then
			READ ( ARG,*) forme
		ENDIF
	END DO

 NMAX=DIM1-1
 NBBANDESUP=0
 NBBANDEINF=0
 N=NBBANDESUP+NBBANDEINF+1


	!ALLOCATION DYNAMIQUE DE LA MEMOIRE 
	!********************POUR LE STOCKAGE COO
	ALLOCATE(VALUES(DIM1))
	ALLOCATE (INDICES(DIM1,2),STAT=IERR)
	!********************POUR LE STOCKAGE CSR
	ALLOCATE (IA(DIM1+1))
	ALLOCATE (JA(DIM1))
	!********************POUR LE STOCKAGE EI
	ALLOCATE (AA(DIM1,NMAX),STAT=IERR)
	ALLOCATE (BB(DIM1,NMAX),STAT=IERR)
	!********************POUR LE STOCKAGE BND
	ALLOCATE (BANDE(DIM1,N),STAT=IERR)
	!********************POUR LA MATRICE PLEINE
	ALLOCATE (U(DIM2))
	ALLOCATE (A(DIM1,DIM2),STAT=IERR)

	ALLOCATE (V(DIM2))



	IF(IERR.NE.0) STOP 'ERREUR pour l allocation des matrices/vecteurs!'

	! PRENONS A LA MATRICE UNITE POUR A ET VALUES
	DO I=1,DIM1
		DO J=1,DIM2
			A(I,J)=0
			U(J)=j;
		END DO
		INDICES(I,1)=I
		INDICES(I,2)=I
		VALUES(I)=1
		A(I,I)=1;
		V(I)=0
		!  IA(I)=1
		! JA(I)=I
	END DO

	!vecteur IA et J equivalent a la matrice unite
	IA(DIM1+1)=1
	DO I=1,DIM1
		IA(I)=1;
		JA(I)=I; 
	END DO  

	!MATRICE AA et BB equivalent a la matrice unite
	DO I=1,DIM1
		AA(I,1)=1
		BB(I,1)=I
	DO J=2,DIM1-1
		AA(I,J)=0
		BB(I,J)=I
	END DO
	END DO
	! !MATRICE BANDE equivalent a la matrice unite
	! DO I=1,DIM1
	!	BANDE(I,NBBANDEINF)=1
	! END DO


	!!!AFFICHONS LA MATRICE I        
	! DO I=1,DIM1
	!   WRITE(*,*) (INDICES(I,J),J=1,2)
	! END DO

	!APPEL DES SUBROUTINES  
	CALL GEMV(A,U,V,DIM1,DIM2,FORME)
	CALL SPMV_COO(INDICES,VALUES,U,V,DIM1)
	CALL SPMV_CSR(IA,JA,VALUES,U,V,DIM1)
	CALL SPMV_EI(AA,BB,U,V,DIM1,NMAX)
	CALL SPMV_BND(BANDE,U,V,DIM1,NBBANDEINF,NBBANDESUP)

	! ON DESALLOUE TOUT CE QU'ON A ALLOUE
	DEALLOCATE(A)
	DEALLOCATE(U)
	DEALLOCATE(INDICES)
	DEALLOCATE(VALUES)
	DEALLOCATE(V)
	DEALLOCATE(IA)
	DEALLOCATE(JA)
	DEALLOCATE(AA)
	DEALLOCATE(BB)

	!END DO

	!-------------------------------------------------------------------------------------------------------------------------------
	!-------------------------------------------------------------------------------------------------------------------------------
	!-------------------------------------------------------------------------------------------------------------------------------
	!-------------------------------------------------ESPACE SUBROUTINES------------------------------------------------------------
	!-------------------------------------------------------------------------------------------------------------------------------
	!-------------------------------------------------------------------------------------------------------------------------------
	!-------------------------------------------------------------------------------------------------------------------------------
	CONTAINS


	!SUBROUTINES MATRICE DENSE
	!-----------------------------------------------------------------------------
	! Fonction : GEMV
	! Description :- calcul leproduit matrice/vecteur dense et enregistre le temps d'execution et les parametre de la matrice dans un fichier
	! Paramètres : - A, la matrice dense
	!              - u, le vecteur multiplie
	!              - v, le vecteur resultat
	! 			 - dim1, int dim2 les dimensions de la matrice
	!              - forme, la forme de la matrice
	! Retour: aucun
	!-----------------------------------------------------------------------------
	SUBROUTINE GEMV(A,U,V,DIM1,DIM2,FORME)
	!DECLARATIONS PARAMETRES
	REAL :: T1,T2,TEMPS_MOY=0.0
	INTEGER, INTENT (IN) :: DIM1,DIM2
	CHARACTER*15, INTENT (IN) :: FORME
	INTEGER :: I,K,COMPTEUR=0,F_COMPTEUR=100
	TYP,DIMENSION(:), INTENT (IN) :: U
	TYP, DIMENSION (:,:), INTENT (IN) :: A
	TYP,DIMENSION(:), INTENT (OUT) :: V

	IF(DIM1 .LT. 100) THEN
		F_COMPTEUR=1000
	ELSE
		F_COMPTEUR = 100
	ENDIF

	!CALCUL PRODUIT
	DO COMPTEUR=1,F_COMPTEUR
		!TOP CHRONO
		CALL CPU_TIME(T1)

		DO I=1,DIM1
			DO K=1,DIM2
			V(I)=V(I)+A(I,K)*U(K)
			END DO
		END DO
		!STOP CHRONO
		CALL CPU_TIME(T2)
		TEMPS_MOY=T2 -T1+TEMPS_MOY
	END DO
	TEMPS_MOY=TEMPS_MOY/F_COMPTEUR
	!   WRITE (6,*) 'TEMPS TOTAL POUR GEMV= ',TEMPS_MOY

	! ECRITURE DES RESULTATS DANS UN FICHIER (ECRITURE SEULE)
	OPEN(13,FILE='dense_F.csv',FORM='FORMATTED',ACTION="WRITE",POSITION="APPEND")
	WRITE(13,'(I3,A3,I3,A3,A15,A3,F8.5)') DIM1,';',DIM2,';',FORME,';',TEMPS_MOY

	!FERMETURE DU FICHIER
	CLOSE(13)

	END SUBROUTINE GEMV

	!SUBROUTINES MATRICE CREUSE FORMAT COO
	!-----------------------------------------------------------------------------
	! Fonction : SPMV_COO
	! Description :- calcul le produit matrice_creuse/vecteur et enregistre le temps d'execution et les parametres de la matrice dans un fichier
	!                pour un stockage creux du type COOrdinate, on a une matrice qui contient les indices des valeurs non nuls de la matrice globale
	!                et un tableau qui contient les valeurs non nuls
	! Paramètres : - int **Indices, la matrice d'indices
	!              - T *Values, le tableau de valeurs non nuls
	!              - T *u, le vecteur multiplie
	!              - T *v, le vecteur resultat
	! 			 - int dim la dimension de la matrice
	!              - char* forme, la forme de la matrice
	! Retour: aucun
	!-----------------------------------------------------------------------------

	SUBROUTINE SPMV_COO(INDICES,VALUES,U,V,DIM1)
	!DECLARATIONS PARAMETRES
	REAL :: T1,T2,TEMPS_MOY=0.0
	INTEGER :: I,K,COMPTEUR=0,F_COMPTEUR=1
	CHARACTER*50 :: FORME="stockage COOrdinate"
	INTEGER, INTENT (IN) :: DIM1
	TYP,DIMENSION(:), INTENT (IN) :: VALUES
	TYP,DIMENSION(:), INTENT (IN) :: U
	INTEGER, DIMENSION (:,:), INTENT (IN) :: INDICES
	TYP,DIMENSION(:), INTENT (OUT):: V

	IF(DIM1 .LT. 100) THEN
		F_COMPTEUR=1000
	ELSE
		F_COMPTEUR = 100
	ENDIF

	!CALCUL PRODUIT
	DO COMPTEUR=1,F_COMPTEUR
		!TOP CHRONO
		CALL CPU_TIME(T1)

		DO I=1,DIM1
			V(INDICES(I,1))=V(INDICES(I,1))+VALUES(I)*U(INDICES(I,2))
		!     WRITE (6,*) V(I)
		END DO

		!STOP CHRONO 
		CALL CPU_TIME(T2)
		TEMPS_MOY=T2 -T1+TEMPS_MOY
	END DO
	TEMPS_MOY=TEMPS_MOY/F_COMPTEUR
	!   WRITE (6,*) 'TEMPS TOTAL POUR SPMV_CLASSIQUE= ',TEMPS_MOY

	!ECRITURE DES RESULTATS DANS UN FICHIER (ECRITURE SEULE)
	OPEN(14,FILE='creuse_F.csv',FORM='FORMATTED',ACTION="WRITE",POSITION="APPEND")
	WRITE(14,'(I3,A3,A15,A3,F8.5)') DIM1,';',FORME,';',TEMPS_MOY
	!FERMETURE DU FICHIER
	CLOSE(14)

	END SUBROUTINE SPMV_COO

	!SUBROUTINES MATRICE CREUSE CSR
	!-----------------------------------------------------------------------------
	! Fonction : SPMV_CSR
	! Description :- calcul le produit matrice_creuse/vecteur et enregistre le temps d'execution et les parametre de la matrice dans un fichier
	!                pour un stockage creux du type Compressed Storage Row, on a un tableau de taille dim+1 qui stocke le nombre d'elements non nuls par ligne
	!                un tableau de taille le nombre de zero qui stocke les numéros des colonne des elements non nuls
	!                et un tableau de taille le nombre de zero qui stocke la valeurs des coefficients non nuls
	! Paramètres : - int *IA, stocke le nombre d'elements non nuls par ligne
	!              - itn *JA stocke les numéros de colonnes des elements non nuls
	!              - T *Values, le tableau de valeurs non nuls
	!              - T *u, le vecteur multiplie
	!              - T *v, le vecteur resultat
	! 			  - int dim la dimension de la matrice
	!              - char* forme, la forme de la matrice
	! Retour: aucun
	!-----------------------------------------------------------------------------
	SUBROUTINE SPMV_CSR(IA,JA,VALUES,U,V,DIM1)
	!DECLARATIONS PARAMETRES
	REAL :: T1,T2,TEMPS_MOY=0.0
	INTEGER :: I,K,COMPTEUR=0,F_COMPTEUR
	CHARACTER*80 :: FORME="stockage Compressed Storage Row"
	INTEGER, INTENT (IN) :: DIM1
	TYP,DIMENSION(:), INTENT (IN) :: VALUES
	TYP,DIMENSION(:), INTENT (IN) :: U
	INTEGER,DIMENSION (:), INTENT (IN) :: IA
	INTEGER,DIMENSION (:), INTENT (IN) :: JA
	TYP,DIMENSION(:), INTENT (OUT):: V

	IF(DIM1 .LT. 100) THEN
		F_COMPTEUR=1000
	ELSE
		F_COMPTEUR = 100
	ENDIF

	!CALCUL PRODUIT
	DO COMPTEUR=1,F_COMPTEUR

		!TOP CHRONO
		CALL CPU_TIME(T1)
		DO I=1,DIM1
			DO K=IA(I),IA(I+1)
				V(I)=V(I)+VALUES(K)*U(JA(K))
		!       WRITE (6,*) V(I)
			END DO
		END DO
		!STOP CHRONO 
		CALL CPU_TIME(T2)

		TEMPS_MOY=T2 -T1+TEMPS_MOY
	END DO
	TEMPS_MOY=TEMPS_MOY/F_COMPTEUR
	!   WRITE (6,*) 'TEMPS TOTAL POUR SPMV_CLASSIQUE= ',TEMPS_MOY

	!ECRITURE DES RESULTATS DANS UN FICHIER (ECRITURE SEULE)
	OPEN(14,FILE='Creuse_F.csv',FORM='FORMATTED',ACTION="WRITE",POSITION="APPEND")
	WRITE(14,'(I3,A3,A15,A3,F8.5)') DIM1,';',FORME,';',TEMPS_MOY
	!FERMETURE DU FICHIER
	CLOSE(14)

	END SUBROUTINE SPMV_CSR


	!SUBROUTINES MATRICE CREUSE EI

	!-----------------------------------------------------------------------------
	! Fonction : SPMV_EI
	! Description :- calcul le produit matrice_creuse/vecteur et enregistre le temps d'execution et les parametre de la matrice dans un fichier
	!                pour un stockage creux du type Ellpack_Itpack, on a 2 tableaux de tailles dim*Nmax, dont un stocke les valeurs des coefficients non nuls par ligne
	!                et un tableau qui contient les numéros de colonne des elements non nuls
	!              - T **AA stocke les valeurs des coefficients non nuls par ligne
	!              - T *u, le vecteur multiplie
	!              - T *v, le vecteur resultat
	! 			   - int dim la dimension de la matrice
	!              - Nmax = max(Nmax[i]) avec Nmax(i], le nombre maximum de valeurs non nuls sur la ligne i
	!              - char* forme, la forme de la matrice
	! Retour: aucun
	!-----------------------------------------------------------------------------  
	SUBROUTINE SPMV_EI(AA,JA,U,V,DIM1,NMAX)
	!DECLARATIONS PARAMETRES
	REAL :: T1,T2,TEMPS_MOY=0.0
	INTEGER :: I,K,COMPTEUR=0,F_COMPTEUR=1
	CHARACTER*80 :: FORME="stockage Ellpack Itpack"
	INTEGER, INTENT (IN) :: DIM1,NMAX
	TYP,DIMENSION(:), INTENT (IN) :: U
	TYP, DIMENSION (:,:), INTENT (IN) :: AA
	INTEGER,DIMENSION (:,:), INTENT (IN) :: JA
	TYP,DIMENSION(:), INTENT (OUT):: V

	IF(DIM1 .LT. 100) THEN
		F_COMPTEUR=1000
	ELSE
		F_COMPTEUR = 100
	ENDIF

	!CALCUL PRODUIT
	DO COMPTEUR=1,F_COMPTEUR

		!TOP CHRONO
		CALL CPU_TIME(T1)
		DO I=1,DIM1
			DO K=1,NMAX
			V(I)=V(I)+AA(I,K)*U(JA(I,K))
			END DO
		END DO
		!       WRITE (6,*) V(I)
		!STOP CHRONO 
		CALL CPU_TIME(T2)

		TEMPS_MOY=T2 -T1+TEMPS_MOY
	END DO
	TEMPS_MOY=TEMPS_MOY/F_COMPTEUR
	!   WRITE (6,*) 'TEMPS TOTAL POUR SPMV_CLASSIQUE= ',TEMPS_MOY

	!ECRITURE DES RESULTATS DANS UN FICHIER (ECRITURE SEULE)
	OPEN(14,FILE='creuse_F.csv',FORM='FORMATTED',ACTION="WRITE",POSITION="APPEND")
	WRITE(14,'(I3,A3,A15,A3,F8.5)') DIM1,';',FORME,';',TEMPS_MOY
	!FERMETURE DU FICHIER
	CLOSE(14)

	END SUBROUTINE SPMV_EI

	!SUBROUTINES MATRICE CREUSE BND

	!-----------------------------------------------------------------------------
	! Fonction : SPMV_BND
	! Description :- calcul le produit matrice_creuse/vecteur et enregistre le temps d'execution et les parametre de la matrice dans un fichier
	!                pour un stockage creux du type Ellpack_Itpack, on a 2 tableaux de tailles dim*Nmax, dont un stocke les valeurs des coefficients non nuls par ligne
	!                et un tableau qui contient les numéros de colonne des elements non nuls
	!              - T **AA stocke les valeurs des coefficients non nuls par ligne
	!              - T *u, le vecteur multiplie
	!              - T *v, le vecteur resultat
	! 			   - int dim la dimension de la matrice
	!              - Nmax = max(Nmax[i]) avec Nmax(i], le nombre maximum de valeurs non nuls sur la ligne i
	!              - char* forme, la forme de la matrice
	! Retour: aucun
	!-----------------------------------------------------------------------------  
	SUBROUTINE SPMV_BND(BANDE,U,V,DIM1,NBBANDEINF,NBBANDESUP)
	!DECLARATIONS PARAMETRES
	REAL :: T1,T2,TEMPS_MOY=0.0
	INTEGER :: I,K,MAXI,MINI,COMPTEUR=0,F_COMPTEUR=1
	CHARACTER*50 :: FORME="stockage BaNDe"
	INTEGER, INTENT (IN) :: DIM1,NBBANDEINF,NBBANDESUP
	TYP,DIMENSION(:), INTENT (IN) :: U
	TYP, DIMENSION (:,:), INTENT (IN) :: BANDE
	TYP,DIMENSION(:), INTENT (OUT):: V

	IF(DIM1 .LT. 100) THEN
		F_COMPTEUR=1000
	ELSE
		F_COMPTEUR = 100
	ENDIF

	!CALCUL PRODUIT
	DO COMPTEUR=1,F_COMPTEUR

		!TOP CHRONO
		CALL CPU_TIME(T1)
		DO I=1,DIM1
			DO K=1,NBBANDEINF+NBBANDESUP+1
				MAXI=MAX(K,K+I-NBBANDEINF)
				MINI=MIN(MAXI,DIM1)
				V(I)=V(I)+BANDE(I,K)*U(MINI)
			END DO
		END DO
		!       WRITE (6,*) V(I)
		!STOP CHRONO 
		CALL CPU_TIME(T2)

		TEMPS_MOY=T2 -T1+TEMPS_MOY
	END DO
	TEMPS_MOY=TEMPS_MOY/F_COMPTEUR
	!   WRITE (6,*) 'TEMPS TOTAL POUR SPMV_CLASSIQUE= ',TEMPS_MOY

	!ECRITURE DES RESULTATS DANS UN FICHIER (ECRITURE SEULE)
	OPEN(14,FILE='creuse_F.csv',FORM='FORMATTED',ACTION="WRITE",POSITION="APPEND")
	WRITE(14,'(I3,A3,A15,A3,F8.5)') DIM1,';',FORME,';',TEMPS_MOY
	!FERMETURE DU FICHIER
	CLOSE(14)

	END SUBROUTINE SPMV_BND

	!-------------------------------------------------------------------------------------------------------------------------------
	!-------------------------------------------------END SUBROUTINES------------------------------------------------------------
	!-------------------------------------------------------------------------------------------------------------------------------
	!-------------------------------------------------------------------------------------------------------------------------------

END PROGRAM PROG_PRINC

!------------------------------------------------------------------------------
!MESSAGE D'ERREUR RETOURNER DANS LE TERMINAL
!a.out: malloc.c:3096: sYSMALLOc: Assertion `(old_top == (((mbinptr) (((char *) &((av)->bins[((1) - 1) * 2])) - __builtin_offsetof (struct malloc_chunk, fd)))) && old_size == 0) || ((unsigned long) (old_size) >= (unsigned long)((((__builtin_offsetof (struct malloc_chunk, fd_nextsize))+((2 * (sizeof(size_t))) - 1)) & ~((2 * (sizeof(size_t))) - 1))) && ((old_top)->size & 0x1) && ((unsigned long)old_end & pagemask) == 0)' failed.
!Abandon
!--------------------------------------------------------------------------------------
